package com.example.flutter_rpsdk;

import android.content.Context;

import androidx.annotation.NonNull;

import com.alibaba.security.biometrics.transition.TransitionMode;
import com.alibaba.security.realidentity.RPConfig;
import com.alibaba.security.realidentity.RPEventListener;
import com.alibaba.security.realidentity.RPResult;
import com.alibaba.security.realidentity.RPVerify;

import java.util.HashMap;
import java.util.Map;

import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry.Registrar;

/** FlutterRpsdkPlugin */
public class FlutterRpsdkPlugin implements FlutterPlugin, MethodCallHandler {
  /// The MethodChannel that will the communication between Flutter and native Android
  ///
  /// This local reference serves to register the plugin with the Flutter Engine and unregister it
  /// when the Flutter Engine is detached from the Activity
  private MethodChannel channel;
  private FlutterPluginBinding mBinding;
  private static Registrar mRegistrar;

  @Override
  public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
    channel = new MethodChannel(flutterPluginBinding.getFlutterEngine().getDartExecutor(), "flutter_rpsdk");
    channel.setMethodCallHandler(this);
    mBinding = flutterPluginBinding;
  }

  // This static function is optional and equivalent to onAttachedToEngine. It supports the old
  // pre-Flutter-1.12 Android projects. You are encouraged to continue supporting
  // plugin registration via this function while apps migrate to use the new Android APIs
  // post-flutter-1.12 via https://flutter.dev/go/android-project-migration.
  //
  // It is encouraged to share logic between onAttachedToEngine and registerWith to keep
  // them functionally equivalent. Only one of onAttachedToEngine or registerWith will be called
  // depending on the user's project. onAttachedToEngine or registerWith must both be defined
  // in the same class.
  public static void registerWith(Registrar registrar) {
    final MethodChannel channel = new MethodChannel(registrar.messenger(), "flutter_rpsdk");
    channel.setMethodCallHandler(new FlutterRpsdkPlugin());
    mRegistrar = registrar;
  }

  private Context getCurrentContext() {
    if(mBinding != null)
      return mBinding.getApplicationContext();
    else{
      return mRegistrar.activeContext();
    }
  }

  static boolean hasKey(Map<String, Object> map, String key) {
    return map.containsKey(key) && map.get(key) != null;
  }

  static RPConfig decodeRPConfig(Map<String, Object> config) {
    RPConfig.Builder rpConfigBuilder = new RPConfig.Builder();

    if(hasKey(config,"buttonTextColor")) {
      rpConfigBuilder.setButtonTextColor((String)config.get("buttonTextColor"));
    }
    if(hasKey(config,"errorTextColor")) {
      rpConfigBuilder.setErrorTextColor((String)config.get("errorTextColor"));
    }
    if(hasKey(config,"needSound")) {
      rpConfigBuilder.setNeedSound((boolean)config.get("needSound"));
    }
    if(hasKey(config,"needWaitingForFinish")) {
      rpConfigBuilder.setNeedWaitingForFinish((boolean)config.get("needWaitingForFinish"));
    }
    if(hasKey(config,"promptTextColor")) {
      rpConfigBuilder.setPromptTextColor((String)config.get("promptTextColor"));
    }
    if(hasKey(config,"showWithDialog")) {
      rpConfigBuilder.setShowWithDialog((boolean)config.get("showWithDialog"));
    }
    if(hasKey(config,"tipTextColor")) {
      rpConfigBuilder.setTipTextColor((String)config.get("tipTextColor"));
    }
    if(hasKey(config,"transitionMode")) {
      rpConfigBuilder.setTransitionMode(TransitionMode.values()[(int)config.get("transitionMode")]);
    }
    if(hasKey(config,"wavesBgColor")) {
      rpConfigBuilder.setWavesBgColor((String)config.get("wavesBgColor"));
    }
    if(hasKey(config,"wavesDetectingColor")) {
      rpConfigBuilder.setWavesDetectingColor((String) config.get("wavesDetectingColor"));
    }
    return new RPConfig(rpConfigBuilder);
  }

  @Override
  public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
    final Context context = this.getCurrentContext();
    final Result mResult = result;
    switch (call.method) {
      case "init":
        RPVerify.init(context);
        result.success(null);
        break;
      case "start": {
        String token = (String) call.argument("token");
        Map<String, Object> config = (Map<String, Object>) call.argument("config");

        RPEventListener listener = new RPEventListener() {
          @Override
          public void onFinish(RPResult auditResult, String code, String msg) {
            Map<String, Object> hashMap = new HashMap<String, Object>();
            hashMap.put("state", auditResult.code);
            hashMap.put("message", msg);
            hashMap.put("code", code);
            mResult.success(hashMap);
          }
        };

        if(config != null) {
          RPConfig rpConfig = decodeRPConfig(config);
          RPVerify.start(context, token, rpConfig, listener);
        } else {
          RPVerify.start(context, token, listener);
        }
      }
        break;
      case "startByNative": {
        String token = (String) call.argument("token");
        Map<String, Object> config = (Map<String, Object>) call.argument("config");
        RPEventListener listener = new RPEventListener() {
          @Override
          public void onFinish(RPResult auditResult, String code, String msg) {
            Map<String, Object> hashMap = new HashMap<String, Object>();
            hashMap.put("code", auditResult.code);
            hashMap.put("msg", auditResult.message);
            mResult.success(hashMap);
          }
        };
        if(config != null) {
          RPConfig rpConfig = decodeRPConfig(config);
          RPVerify.startByNative(context, token, rpConfig, listener);
        } else {
          RPVerify.startByNative(context, token, listener);
        }
      }
        default:
          result.notImplemented();
          break;
    }
  }

  @Override
  public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
    channel.setMethodCallHandler(null);
  }
}
